package com.zhangfb95.crosschain.infra.model;

import com.zhangfb95.crosschain.infra.exception.BusinessException;
import com.zhangfb95.crosschain.infra.statuscode.IStatusCode;
import com.zhangfb95.crosschain.infra.statuscode.StatusCode;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.function.Function;

/**
 * 统一的返回结果，作为服务间进行通信的数据协议。<br/>
 * code表示状态码，不同服务不同接口会返回不同的状态码<br/>
 * msg表示返回的结果信息描述<br/>
 * data作为泛型参数类型，在不同接口可以定义不同的类型
 *
 * @param <T> 数据泛型类型
 * @author zhangfubing
 */
@Accessors(chain = true)
@Data
public class Result<T> {

    /**
     * 成功标记
     */
    private boolean success = true;

    /**
     * 状态码
     */
    private String code = StatusCode.OK.getCode();

    /**
     * 描述
     */
    private String msg = StatusCode.OK.getMsg();

    /**
     * 挂载数据
     */
    private T data;

    public static <R> Result<R> ok() {
        return new Result<>();
    }

    public static <R> Result<R> ok(String msg, R data) {
        return new Result<R>().setMsg(msg).setData(data);
    }

    public static <R> Result<R> ok(R data) {
        return new Result<R>().setData(data);
    }

    public static <R> Result<R> ok(String msg) {
        return new Result<R>().setMsg(msg);
    }

    public static <R> Result<R> fail(String msg) {
        return new Result<R>().setSuccess(false).setCode(StatusCode.COMMON_ERROR.getCode()).setMsg(msg);
    }

    public static <R> Result<R> fail(IStatusCode statusCode) {
        return new Result<R>().setSuccess(StatusCode.OK.is(statusCode)).setCode(statusCode.getCode()).setMsg(statusCode.getMsg());
    }

    public static <R> Result<R> fail(String code, String msg) {
        return new Result<R>().setSuccess(StatusCode.OK.is(code)).setCode(code).setMsg(msg);
    }

    public static <R> Result<R> fail(String code, String msg, R data) {
        return new Result<R>().setSuccess(StatusCode.OK.is(code)).setCode(code).setMsg(msg).setData(data);
    }

    public static <R> Result<R> copy(Result<?> from) {
        return from.copy();
    }

    public <R> Result<R> copy(Function<T, R> function) {
        Result<R> result = copy();
        if (function != null) {
            result.data = function.apply(this.data);
        }
        return result;
    }

    public <R> Result<R> copy() {
        Result<R> result = new Result<>();
        result.success = this.success;
        result.code = this.code;
        result.msg = this.msg;
        return result;
    }

    public Result<T> fallback() {
        return fallback(code, msg, data);
    }

    public Result<T> fallback(String msg) {
        return fallback(code, msg, data);
    }

    public Result<T> fallback4Code(String code) {
        return fallback(code, msg, data);
    }

    public Result<T> fallback(String code, String msg) {
        return fallback(code, msg, data);
    }

    /**
     * 失败时抛出业务异常
     *
     * @param code 状态码
     * @param msg  描述
     * @param data 挂载数据
     * @return 当前对象
     */
    public Result<T> fallback(String code, String msg, Object data) {
        if (!success) {
            throw new BusinessException(code, msg, data);
        }
        return this;
    }
}
